package probe.sound.core;

import java.io.InputStream;
import java.io.RandomAccessFile;

import probe.sound.code.Util;
import probe.sound.resources.Resources;

public class SynWave implements Syn {
  
  private Producer producer;
  private double timeDelay;
  private String outFileName;
  
  public SynWave() {}
  
  public SynWave(String outFileName) {
    this.outFileName = outFileName;
  }
  
  @Override
  public void setProducer(Producer producer) {
    this.producer = producer;
  }
  
  @Override
  public void setTimeDelay(double timeDelay) {
    this.timeDelay = timeDelay;
  }
  
  public void setOutFileName(String outFileName) {
    this.outFileName = outFileName;
  }
  
  @Override
  public void run() {
    try {
      runInner();
    } catch (Exception e) {
      if (e instanceof RuntimeException) throw (RuntimeException)e;
      throw new RuntimeException( e );
    }
  }
  
  private void runInner() throws Exception {
    RandomAccessFile f = new RandomAccessFile( outFileName, "rw" );
    
    f.seek( 44 );
    int dataSize = 0;
    
    byte[] buf = new byte[1024];
    
    int iCount = buf.length / 4;
    
    final Value value = new Value();
    
    U: for (int u = 0; true; u++) {
      int bufferFilledOn = buf.length;
      I: for (int i = 0; i < iCount; i++) {
        
        int iSample = u * iCount + i;
        
        double t = ((double)iSample) / SAMPLE_RATE; //time in seconds
        
        if (t > timeDelay) {
          bufferFilledOn = i * 4;
          break I;
        }
        value.clean();
        
        producer.produce( value, t );
        
        int left = Util.toSignedWord( value.left );
        int right = Util.toSignedWord( value.right );
        
        Util.writeWord( buf, 4 * i + 0, true, left );
        Util.writeWord( buf, 4 * i + 2, true, right );
      }
      
      if (bufferFilledOn == 0) break U;
      
      f.write( buf, 0, bufferFilledOn );
      dataSize += bufferFilledOn;
      
    }
    
    f.seek( 0 );
    
    InputStream in = Resources.class.getResourceAsStream( "wave.header.bin" );
    byte header[] = new byte[44];
    int readToHeader = in.read( header );
    in.close();
    if (readToHeader != header.length) {
      f.close();
      throw new RuntimeException( "Left header" );
    }
    
    Util.writeInt4( header, 40, true, dataSize );
    
    f.write( header );
    
    f.close();
  }
  
}
